#coding:utf-8
'''
create on 2017-05-05

@author:sandy
'''

#添加'S'支持 底层发送时候还是以's'发送 字节长度比's'长
import struct
import logging
import time
ENDIAN_LITTLE = u"<"
ENDIAN_BIG = u">"
ENDIAN_DEFAULT = ENDIAN_BIG
STRLEN_CHAR0 = u"B"
STRLEN_CHAR1 = u"H"
STRLEN_CHAR2 = u"I"
SPECIAL_CHAR = {'s':STRLEN_CHAR1,'S':STRLEN_CHAR2}

############################################ private ###################################

def __compressed(format,data):
    pack = ""
    he = format[0] 
    for i in range(len(data)):
        ch = format[i+1]
        if ch == 's' or ch == 'S':
            length = len(data[i])
            l = struct.pack(he + SPECIAL_CHAR.get(ch),length);
            d = struct.pack(he + str(length) + 's',data[i]);
            pack = pack + l + d
            pass
        else:
            pack += struct.pack(he + ch,data[i])

    return pack

def __uncompressed(format,pkt,index):
    data = []
    he = format[0]
    pkt = pkt[index:]
    for i in range(1,len(format)):
        ch = format[i]
        if ch == 's' or ch == 'S':
            l = struct.calcsize(SPECIAL_CHAR.get(ch))
            d = struct.unpack(he + SPECIAL_CHAR.get(ch),pkt[:l])
            pkt = pkt[l:]
            l = struct.calcsize('s')
            f = he + str(*d) + 's'
            l = int(*d) * l
            d = struct.unpack(f,pkt[:l])
            data.append(*d)
            pkt = pkt[l:]
        else:
            l = struct.calcsize(ch)
            d = struct.unpack(he + ch,pkt[:l])
            data.append(*d)
            pkt = pkt[l:]
    return data

########################################## public ########################################
def pack(arg, *args):
    returnData = u""
    if len(arg) > 0:
        if (arg[0] == ENDIAN_LITTLE or arg[0] == ENDIAN_BIG) and (arg[0] != ENDIAN_DEFAULT):
            logging.error(u"CurPack is error,use='%s' but system='%s'",arg[0],ENDIAN_DEFAULT)
            return
        if arg[0] != ENDIAN_LITTLE and arg[0] != ENDIAN_BIG:
            arg = ENDIAN_DEFAULT + arg
        if len(arg) == len(args) + 1:
            returnData = __compressed(arg,args)
        else:
            logging.error(u'pack.pack dataLen error')
    else:
        logging.error(u"pack.pack dataFormat error")
    return returnData

def unpack(arg,pkt,index = 0):
    data = []
    if len(arg) > 0:
        if (arg[0] == ENDIAN_LITTLE or arg[0] == ENDIAN_BIG) and (arg[0] != ENDIAN_DEFAULT):
            logging.error(u"CurUnPack is error,use='%s' but system='%s'",arg[0],ENDIAN_DEFAULT)
            return
        if arg[0] != ENDIAN_LITTLE and arg[0] != ENDIAN_BIG:
            arg = ENDIAN_DEFAULT + arg
        data = __uncompressed(arg,pkt,index)
    else:
        logging.error(u"pack.unpack dataFormat error")
    if len(data) == 1:
        return data[0]
    else:
        return tuple(data)

if __name__ == '__main__':
    pass